import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Scanner;
public class GenerateSignature {

	/**
	 * @param args
	 * @throws UnsupportedEncodingException 
	 * @throws NoSuchAlgorithmException 
	 */
	public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {
		Scanner scan= new Scanner(System.in);
		 //byte[] keyBytes = ("this is my key").getBytes("UTF-8");
		// keyBytes = Arrays.copyOf(keyBytes, 16);
		 KeyGenerator keygen=KeyGenerator.getInstance("AES");
		 keygen.init(128);
		 SecretKey skey=keygen.generateKey();
		 Boolean run=true;
		while(run){
		System.out.println("Press 1 for signing your file and 2 for verifying your file and 3 for terminating program:");
		int choice = scan.nextInt();
		scan.nextLine();
		
		switch(choice){
		case 1:
			System.out.println("Generating private and public key..");
			try{
				//read in file
				scan.reset();
				System.out.println("Write path to the data file:");
				String path=scan.nextLine();
				String folderPath=path.substring(0, path.lastIndexOf("client 1"));
				File file= new File(path);
				byte[] data = new byte[(int)file.length()];
				FileInputStream fileInput=new FileInputStream(file);
				fileInput.read(data);
				//encrypt byte data
				System.out.println("input text : " + new String(data));
				Cipher c = Cipher.getInstance("AES");
				//SecretKeySpec k = new SecretKeySpec(keyBytes, "AES");
				c.init(Cipher.ENCRYPT_MODE, skey);
				byte[] encryptedData = c.doFinal(data);
				System.out.println("encrypted data: " + new String(encryptedData));
				
				//save encrypted data in file
				FileOutputStream fos = new FileOutputStream(folderPath+"client 2\\encryptedData");
		        fos.write(encryptedData);
			    fos.close();
			     
			    //make private and public key for signature 
				 
				System.out.println("Generating private and public key");
				KeyPairGenerator keyGen= KeyPairGenerator.getInstance("RSA");
				SecureRandom random=SecureRandom.getInstance("SHA1PRNG", "SUN");
				keyGen.initialize(1024, random);
				KeyPair pair=keyGen.generateKeyPair();
				PrivateKey privateK=pair.getPrivate();
				PublicKey publicK=pair.getPublic();
			
				System.out.println("Generating signature for file");
				Signature sigDSA=Signature.getInstance("SHA1withRSA");
				sigDSA.initSign(privateK);
				FileInputStream fis=new FileInputStream(folderPath+"\\client 2\\encryptedData");
				BufferedInputStream buf= new BufferedInputStream(fis);
				byte[] buffer=new byte[1024];
				int len;
				while((len=buf.read(buffer))>=0){
					sigDSA.update(buffer, 0, len);
				}
				buf.close();
				byte [] finalSig=sigDSA.sign();
				/* save the signature in a file */
				FileOutputStream sigfos = new FileOutputStream(folderPath+"\\client 2\\signedFile");
				sigfos.write(finalSig);
				sigfos.close();
				/* save the public key in a file */
				byte[] publicKey = publicK.getEncoded();
				FileOutputStream keyfos = new FileOutputStream(folderPath+"client 2\\publicKey");
				keyfos.write(publicKey);
				keyfos.close();
				
				
		}
			catch(Exception e){
				System.err.println(e.getMessage());
			}
			break;
		case 2:
			try{
				System.out.println("Write path to the folder where public key, signed file and ecrypted data is located:");
				String folderPathPubAndSig=scan.nextLine();
				System.out.println("getting public key");
				FileInputStream keyInput = new FileInputStream(folderPathPubAndSig+"\\publicKey");
				byte[] encKey = new byte[keyInput.available()];  
				keyInput.read(encKey);

				keyInput.close();
				
				X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
				
				KeyFactory keyFactory = KeyFactory.getInstance("RSA");
				
				PublicKey pubKey =   keyFactory.generatePublic(pubKeySpec);
				System.out.println("getting signed file");
				FileInputStream sigInput = new FileInputStream(folderPathPubAndSig+"\\signedFile");
				byte[] sigToVerify = new byte[sigInput.available()]; 
				
				sigInput.read(sigToVerify);
				sigInput.close();
				
				Signature sig = Signature.getInstance("SHA1withRSA");
				sig.initVerify(pubKey);
				System.out.println("getting ecrypted data");
				FileInputStream dataInput = new FileInputStream(folderPathPubAndSig+"\\encryptedData");
				BufferedInputStream bufin = new BufferedInputStream(dataInput);

				byte[] buffer = new byte[1024];
				int len;
				while (bufin.available() != 0) {
				    len = bufin.read(buffer);
				    sig.update(buffer, 0, len);
				};

				bufin.close();
				boolean verifies = sig.verify(sigToVerify);

				System.out.println("signature verifies: " + verifies);
				if(verifies){
					System.out.println("the decrypted messeage: ");
					File file= new File(folderPathPubAndSig+"\\encryptedData");
					byte[] encryptedData = new byte[(int)file.length()];
					FileInputStream fileInput=new FileInputStream(file);
					fileInput.read(encryptedData);
					Cipher c = Cipher.getInstance("AES");
					//SecretKeySpec k = new SecretKeySpec(keyBytes, "AES");
					c.init(Cipher.DECRYPT_MODE, skey);
					byte[] decryptData = c.doFinal(encryptedData);
					System.out.println("Decrypted data: " + new String(decryptData));
				}
			}
			catch(Exception e2)
			{
				
			}
			break;
		case 3:
			run=false;
			break;
		
		}
		
		}
		
		
	}
	
	

}
